home *** CD-ROM | disk | FTP | other *** search
- ******************************************************************
- * COPYRIGHT (C) 1986 by Donald Krantz and James Stanley
- * - Note: This is a real, live, actual, registered copyright,
- * and should be treated as such. This source code is from
- * the book "68000 Assembly Language", Krantz and Stanley,
- * Addison-Wesley Publishing Company, Reading, MA, 1986.
- *
- * Permission granted by the authors for non-commercial use
- * in programs released to the public domain, as long as this
- * copyright notice remains attached and visible.
- *
- *****************************************************************
- * BITPRIM - bit mapped graphics primitives
- #bit.h
-
- xref image,sqrt
- xdef g_pix,g_mode,g_vector,g_circle,g_clear,g_fill
- xdef mode
-
- *****************************************************************
- * SET_PIX - sets the pixel where D0.W = X and D1.W = Y
- g_pix:
- movem.l d0/d1/a0,-(a7) * save caller's registers
- *
- cmp.w #hor_b,d0 * check clipping horizontal
- bcc sk0_sp * exit on over X
- cmp.w #vert,d1 * check clipping vertical
- bcc sk0_sp * exit on over Y
- *
- move.l #image,a0 * get base of image area
- mulu #(hor_w*2),d1 * get vertical offset to line
- add.l d1,a0 * and add to base address
- move.w d0,d1 * save X for later
- lsr.w #3,d0 * get number of bytes to pixel
- add.w d0,a0 * add to pointer
- and.w #$0007,d1 * strip all but bit number
- move.w mode,d0 * get mode flag
- lsr.w #1,d0 * pop bit 0 into carry flag
- bcs sk1_sp * jam mode jump
- lsr.w #1,d0 * pop bit 1 into carry flag
- bcs sk2_sp * complement mode jump
- lsr.w #1,d0 * pop bit 2 into carry flag
- bcs sk3_sp * set mode jump
- bclr d1,(a0) * falls thru to clear mode
- bra sk0_sp * so we're done
- sk1_sp:
- sk3_sp:
- bset d1,(a0) * jam and set are the same here
- bra sk0_sp * now we're done
- sk2_sp:
- bchg d1,(a0) * complement mode
- sk0_sp:
- movem.l (a7)+,d0/d1/a0 * restore caller's registers
- rts
- *****************************************************************
- * SET_MODE - Sets mode to value contained in D0.W
- g_mode:
- move.w d0,mode
- rts
- *****************************************************************
- * G_VECTOR - draws a vector from (D0.W,D1.W) to (D2.W,D3.W)
- g_vector:
- movem.l d0-d7,-(a7) * Save registers
- ******* Scale and save vector origin coordinates ****************
- move.w d0,d4 * setup base for X
- swap d4 * scale x 2^16
- clr.w d4 * make even number
- move.w d1,d5 * setup base for Y
- swap d5 * scale x 2^16
- clr.w d5 * make even number
- ******* Determine absolute and signed run in X ******************
- sub.w d0,d2 * find difference in X
- move.w d2,d0 * save signed difference
- bpl sk1_vec * skip X absolute value convert
- neg.w d0 * D0 is X absolute distance
- ******* Determine absolute and signed run in Y ******************
- sk1_vec:
- sub.w d1,d3 * find difference in Y
- move.w d3,d1 * save signed difference
- bpl sk2_vec * skip Y absolute value convert
- neg.w d1 * D1 is Y absolute distance
- ******* Determine independent (larger) and dependent axis *******
- sk2_vec:
- cmp.w d0,d1 * see if X dif > Y dif
- bgt Y_bigger * jump if y is bigger
- ******* X is independent axis - determine X step as +/- 1.0 *****
- tst.w d2 * check sign of X run
- bmi sk3_vec * jump if negative
- move.l #$00010000,d6 * setup X step = 1.0
- bra sk4_vec * jump to Y setup
- sk3_vec:
- move.l #$FFFF0000,d6 * setup Y step = -1.0
- ******* Determine Y step as scaled fixed point longword *********
- sk4_vec:
- swap d3 * Scale up
- clr.w d3 * make longword
- asr.l #2,d3 * take out two bits of precision
- divs d0,d3 * divide by independent axis
- ext.l d3 * make long again
- asl.l #2,d3 * put two precisions bits back
- move.l d3,d7 * D7 is signed Y step
- move.w d0,d2 * get independant axis counter
- bra sk7_vec * go do output
- ******* Y is independent axis - setup Y step as +/- 1.0 *********
- Y_bigger:
- tst.w d3 * check sign of Y run
- bmi sk5_vec * jump if step negative
- move.l #$00010000,d7 * make Y step 1.0
- bra sk6_vec * jump to X setup
- sk5_vec:
- move.l #$FFFF0000,d7 * make Y step -1.0
- ******* Determine X step as scaled fixed point longword *********
- sk6_vec:
- swap d2 * Scale up
- clr.w d2 * make longword
- asr.l #2,d2 * Take out two bits of precision
- divs d1,d2 * divide by independent axis
- ext.l d2 * make long again
- asl.l #2,d2 * put back the precision
- move.l d2,d6 * D6 is signed X step
- move.w d1,d2 * get independant axis counter
- *
- ******* Pixel output loop ***************************************
- sk7_vec:
- bra sk8_vec * do loop test before body
- lp0_vec:
- move.l d4,d0 * get scaled X position
- add.l #$00008000,d0 * round up by adding 0.5
- swap d0 * scale X down for output
- move.l d5,d1 * get scaled Y position
- add.l #$00008000,d1 * round up by adding 0.5
- swap d1 * scale Y down for output
- bsr g_pix * put the pixel
- add.l d6,d4 * add X step
- add.l d7,d5 * add Y step
- sk8_vec:
- dbra d2,lp0_vec * loop around
- movem.l (a7)+,d0-d7 * restore registers
- rts
- *****************************************************************
- * Draws a circle around (D0.W,D1.W) of radius D2.W
- g_circle:
- movem.l d0-d7,-(a7) * Save registers
- move.w d0,d6 * d6 will be X base pixel
- move.w d1,d7 * d7 will be Y base pixel
- move.w d2,d3 * get copy of radius
- mulu d3,d3 * d3.l is radius squared
- swap d2 * make into scaled longword
- clr.w d2 * truncate
- divu #$B504,d2 * radius / (sqr(2) << 15)
- add.w #1,d2 * round up
- asr.l #1,d2 * align D2 because sqr(2) scaled
- lp0_cir:
- move.w d2,d4 * d4 is a scratch register
- mulu d4,d4 * d4 is (rise**2)
- move.l d3,d0 * d0 is scratch register
- sub.l d4,d0 * d0 is (run**2)
- bsr sqrt * after call, d0 = (run)
- move.w d0,d4 * save run
- ******* Quadrant I, counterclockwise
- move.w d6,d0 * X center
- move.w d7,d1 * Y center
- add.w d4,d0 * add run
- add.w d2,d1 * add rise
- bsr g_pix
- ******* Quadrant I, clockwise
- move.w d6,d0 * X center
- move.w d7,d1 * Y center
- add.w d4,d1 * add rise
- add.w d2,d0 * add run
- bsr g_pix
- ******* Quadrant II, counterclockwise
- move.w d6,d0 * X center
- move.w d7,d1 * Y center
- sub.w d2,d0 * add rise
- add.w d4,d1 * add run
- bsr g_pix
- ******* Quadrant II, clockwise
- move.w d6,d0 * X center
- move.w d7,d1 * Y center
- add.w d2,d1 * add rise
- sub.w d4,d0 * add run
- bsr g_pix
- ******* Quadrant III, counterclockwise
- move.w d6,d0 * X center
- move.w d7,d1 * Y center
- sub.w d2,d1 * add rise
- sub.w d4,d0 * add run
- bsr g_pix
- ******* Quadrant III, clockwise
- move.w d6,d0 * X center
- move.w d7,d1 * Y center
- sub.w d2,d0 * add rise
- sub.w d4,d1 * add run
- bsr g_pix
- ******* Quadrant IV, counterclockwise
- move.w d6,d0 * X center
- move.w d7,d1 * Y center
- add.w d2,d0 * add rise
- sub.w d4,d1 * add run
- bsr g_pix
- ******* Quadrant IV, clockwise
- move.w d6,d0 * X center
- move.w d7,d1 * Y center
- add.w d4,d0 * add run
- sub.w d2,d1 * add rise
- bsr g_pix
- dbra d2,lp0_cir * loop for next set
- movem.l (a7)+,d0-d7 * Restore registers
- rts
- *****************************************************************
- * Clears the graphics image area
- g_clear:
- movem.l a0/d0,-(a7) * save registers
- move.l #image,a0 * Get image area base address
- move.l #(vert*hor_w/2),d0
- lp0_cl:
- clr.l (a0)+ * zero out byte
- subq.l #1,d0 * pop counter
- bne lp0_cl * loop for next
- movem.l (a7)+,a0/d0 * restore registers
- rts
- *****************************************************************
- * Fills the area bounded by (D0.W,D1.W) and (D2.W,D3.W)
- g_fill:
- movem.l d0-d7/a0/a1,-(a7) save callers registers
- ******* Adjust so that D2.W >= D0.W and D3.W >= D1.W
- cmp.w d0,d2 * Who's bigger?
- bge sk1_fil * jump if d2 is bigger
- exg d0,d2 * swap if not
- sk1_fil:
- cmp.w d1,d3 * Who's bigger here?
- bge sk2_fil * jump if d3 is bigger
- exg d1,d3 * swap if not
- sk2_fil:
- ******* Calculate (number of rows) - 1, save in D7
- move.w d3,d7 * uses D7 as accumulator
- sub.w d1,d7 * D7 is (#rows-1)
- ******* Calculate first byte address in A0
- move.l #image,a0 * A0 is base of image memory
- mulu #(hor_w*2),d1 * D1 is row offset from zero
- move.w d0,d3 * D3 is a scratch register
- asr.w #3,d3 * D3 is number of bytes into row
- add.w d3,d1 * D1 is bytes into image
- add.w d1,a0 * A0 is now address of first byte
- ******* Make mask for left fragment in D4.B
- move.w d0,d1 * D1 is scratch register
- and.w #$0007,d1 * D1 is pixel address
- move.w #$00FF,d4 * D4 will be fragment mask
- lsl.b d1,d4 * move mask to correct pixels
- ******* Make mask for right fragment in D6.B
- move.w d2,d1 * D1 is scratch register
- and.w #$07,d1 * D1 is pixel address
- move.w #$FE01,d6 * D6 will be fragment mask
- rol.w d1,d6 * move mask to correct pixels
- ******* Compute distance 'twixt start and end byte in row
- lsr.w #3,d0 * get starting offset into row
- lsr.w #3,d2 * get ending offset into row
- ******* Test for special case - left and right frags in same byte
- sub.w d0,d2 * are they the same?
- bne sk3_fil * jump if not...
- ******* process start/end in same byte
- and.b d6,d4 * combine the two masks
- btst #0,mode+1 * look for jam mode
- bne sk4_fil * go jam
- btst #1,mode+1 * look for complement mode
- bne sk5_fil * go complement
- btst #2,mode+1 * look for set mode
- bne sk4_fil * it's the same as jam here
- ******* must be clear mode, special case. Let's do it! (yay!) ***
- not.b d4 * invert the mask
- lp1_fil:
- and.b d4,(a0) * reset the right bits
- add.l #(hor_w*2),a0 * move the address to next row
- dbra d7,lp1_fil * and repeat as necessary
- bra ex_fill * finished!
- ******* jam or set mode, special case ***************************
- sk4_fil:
- or.b d4,(a0) * set the right bits
- add.l #(hor_w*2),a0 * move the address to next row
- dbra d7,sk4_fil * and repeat
- bra ex_fill * exit
- ******* complement mode, special case ***************************
- sk5_fil:
- eor.b d4,(a0) * complement the right bits
- add.l #(hor_w*2),a0 * move the address to next row
- dbra d7,sk4_fil * repeat
- bra ex_fill * exit
- ******* normal (multi-byte/row) fill case continued *************
- sk3_fil:
- subq.w #1,d2 * d2 is now number of whole bytes
- btst #0,mode+1 * look for jam mode
- bne sk6_fil * go jam
- btst #1,mode+1 * look for complement mode
- bne sk7_fil * go complement
- btst #2,mode+1 * look for set mode
- bne sk6_fil * it's the same as jam here
- ******* Must be clear mode, normal case *************************
- not.b d4 * invert start mask
- not.b d6 * invert end mask
- lp2_fil:
- move.w d2,d5 * Have to save d2
- move.l a0,a1 * A1 can be modified, A0 can't.
- and.b d4,(a1)+ * catch left-hand bits
- bra sk8_fil * do loop test before body
- lp3_fil:
- clr.b (a1)+ * zero out middle bytes
- sk8_fil:
- dbra d5,lp3_fil * repeat for middle bytes
- and.b d6,(a1) * get right-hand bits
- add.l #(hor_w*2),a0 * move to next row
- dbra d7,lp2_fil * repeat for all rows
- bra ex_fill * and quit
- ******* Jam or Set mode, normal case ****************************
- sk6_fil:
- move.w d2,d5 * Have to save d2
- move.l a0,a1 * A1 can be modified, A0 can't.
- or.b d4,(a1)+ * catch left-hand bits
- bra sk9_fil * do loop test before body
- lp4_fil:
- move.b #$FF,(a1)+ * set middle bytes
- sk9_fil:
- dbra d5,lp4_fil * repeat for middle bytes
- or.b d6,(a1) * get right-hand bits
- add.l #(hor_w*2),a0 * move to next row
- dbra d7,sk6_fil * repeat for all rows
- bra ex_fill * and quit
- ******* Complement mode, normal case ****************************
- sk7_fil:
- move.w d2,d5 * Have to save d2
- move.l a0,a1 * A1 can be modified, A0 can't.
- eor.b d4,(a1)+ * catch left-hand bits
- bra sk10_fil * do loop test before body
- lp5_fil:
- eor.b #$FF,(a1)+ * zero out middle bytes
- sk10_fil:
- dbra d5,lp5_fil * repeat for middle bytes
- eor.b d6,(a1) * get right-hand bits
- add.l #(hor_w*2),a0 * move to next row
- dbra d7,sk7_fil * repeat for all rows
- ******* fill procedure common exit ******************************
- ex_fill:
- movem.l (a7)+,d0-d7/a0/a1 restore registers
- rts
- *****************************************************************
-
- data
- mode dc.w jam_m * start in jam mode
-
- end